package com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl;

import com.derbysoft.dswitch.adapter.ihg.common.domain.HotelMapping;
import com.derbysoft.dswitch.adapter.ihg.common.domain.ReservationItem;
import com.derbysoft.dswitch.adapter.ihg.common.repository.ReservationItemRepository;
import com.derbysoft.dswitch.adapter.ihg.common.utils.CollectionUtil;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.Translator;
import com.derbysoft.dswitch.adapter.ihg.dto.*;
import com.derbysoft.dswitch.adapter.ihg.exception.ConfirmNumberNotFoundException;
import com.derbysoft.dswitch.dto.hotel.common.*;
import com.derbysoft.dswitch.dto.hotel.reservation.HotelReservationDTO;
import com.derbysoft.dswitch.dto.hotel.reservation.ReservationRoomStayDTO;
import com.derbysoft.dswitch.remote.hotel.dto.HotelReservationRequest;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by: jason
 * Date: 2012-05-14
 */
@Component("hotelCommitRQTranslator")
public class HotelCommitRQTranslatorImpl extends BaseTranslator
        implements Translator<HotelReservationRequest, OTAHotelResRQ, Void> {

    public static final String DEFAULT_GUARANTEE_CODE = "GX";
    private static final String RESERVATION_RESPONSE_TYPE = "Full Response";
    private static final String MODIFY = "Modify";

    @Autowired
    private ReservationItemRepository reservationItemRepository;

    @Override
    public OTAHotelResRQ translate(HotelReservationRequest reservationRequest, Void aVoid) {
        OTAHotelResRQ otaHotelResRQ = new OTAHotelResRQ();
        setRequestAttributes(otaHotelResRQ, reservationRequest);
        if (reservationRequest.getHotelReservationRQ().getResActionType() == TransactionActionType.MODIFY) {
            otaHotelResRQ.setResStatus(MODIFY);
        }
        otaHotelResRQ.setHotelReservations(createHotelReservations(reservationRequest));
        return otaHotelResRQ;
    }

    private HotelReservations createHotelReservations(HotelReservationRequest reservationRequest) {
        HotelReservations hotelReservations = new HotelReservations();
        hotelReservations.getHotelReservation().add(createHotelReservation(reservationRequest));
        return hotelReservations;
    }

    private HotelReservation createHotelReservation(HotelReservationRequest reservationRequest) {
        HotelReservation hotelReservation = new HotelReservation();
        hotelReservation.setResGuests(createResGuests(reservationRequest));
        hotelReservation.setRoomStays(createRoomStays(reservationRequest));
        hotelReservation.setRoomStayReservation(Boolean.TRUE);
        ReservationRsTpaExtensions tpaExtensions = new ReservationRsTpaExtensions();
        ResponseType responseType = new ResponseType();
        responseType.setResponse(RESERVATION_RESPONSE_TYPE);
        tpaExtensions.setResponseType(responseType);
        hotelReservation.setTPAExtensions(tpaExtensions);
        if (reservationRequest.getHotelReservationRQ().getResActionType() == TransactionActionType.MODIFY) {
            hotelReservation.setResGlobalInfo(createResGlobalInfo(reservationRequest.getHotelReservationRQ().getErsp()));
        }
        return hotelReservation;
    }

    private ResGlobalInfo createResGlobalInfo(String erspNumber) {
        ResGlobalInfo resGlobalInfo = new ResGlobalInfo();
        HotelReservationIDs hotelReservationIDs = new HotelReservationIDs();
        HotelReservationID hotelReservationID = new HotelReservationID();
        hotelReservationID.setForGuest(false);
        hotelReservationID.setResIDType("14");
        hotelReservationID.setResIDValue(findConfirmNo(erspNumber));
        hotelReservationIDs.getHotelReservationID().add(hotelReservationID);
        resGlobalInfo.setHotelReservationIDs(hotelReservationIDs);
        return resGlobalInfo;
    }

    private String findConfirmNo(String erspNumber) {
        ReservationItem reservationItem = reservationItemRepository.loadByErsp(erspNumber);
        if (reservationItem == null || reservationItem.getConfirmNumber() == null) {
            throw new ConfirmNumberNotFoundException("ersp :" + erspNumber);
        }
        return reservationItem.getConfirmNumber();
    }

    private ReservationRoomStays createRoomStays(HotelReservationRequest reservationRequest) {
        ReservationRoomStay roomStay = new ReservationRoomStay();
        HotelReservationDTO hotelReservation = reservationRequest.getHotelReservationRQ().getHotelReservation();
        ReservationRoomStayDTO reservationRoomStayDTO = hotelReservation.getRoomStaysList().get(0);

        roomStay.setBasicPropertyInfo(translateBasicPropertyInfo(hotelReservation.getHotelCode()));
        roomStay.setTimeSpan(translateTimeSpan(reservationRoomStayDTO.getStayDateRange()));
        roomStay.setGuarantee(translateGuarantee());
        GuestCounts guestCounts = new GuestCounts();
        guestCounts.getGuestCount().addAll(translateGuestCounts(reservationRoomStayDTO));
        guestCounts.setIsPerRoom(false);
        roomStay.setGuestCounts(guestCounts);
        RoomTypes roomTypes = new RoomTypes();
        roomTypes.getRoomType().add(translateRoomType(reservationRoomStayDTO));
        roomStay.setRoomTypes(roomTypes);
        RatePlans ratePlans = new RatePlans();
        ratePlans.getRatePlan().add(translateRatePlan(reservationRoomStayDTO));
        roomStay.setRatePlans(ratePlans);
        ReservationRoomStays reservationRoomStays = new ReservationRoomStays();
        reservationRoomStays.getRoomStay().add(roomStay);
        return reservationRoomStays;
    }

    private RatePlan translateRatePlan(ReservationRoomStayDTO reservationRoomStay) {
        RatePlan ratePlan = new RatePlan();
        ratePlan.setRatePlanCode(reservationRoomStay.getRatePlanCode());
        return ratePlan;
    }

    private RoomType translateRoomType(ReservationRoomStayDTO reservationRoomStay) {
        RoomType roomType = new RoomType();
        roomType.setRoomTypeCode(reservationRoomStay.getRoomTypeCode() + reservationRoomStay.getRatePlanCode());
        roomType.setNumberOfUnits(reservationRoomStay.getNumberOfUnits());
        return roomType;
    }

    private TimeSpan translateTimeSpan(StayDateRangeDTO stayDateRange) {
        TimeSpan timeSpan = new TimeSpan();
        timeSpan.setStart(stayDateRange.getCheckin());
        timeSpan.setEnd(stayDateRange.getCheckout());
        return timeSpan;
    }

    private BasicPropertyInfo translateBasicPropertyInfo(String hotelCode) {
        HotelMapping hotelMapping = loadHotel(hotelCode);
        BasicPropertyInfo basicPropertyInfo = new BasicPropertyInfo();
        basicPropertyInfo.setHotelCode(hotelMapping.getCooperatorCode());
        basicPropertyInfo.setHotelName(hotelMapping.getHotelName());
        return basicPropertyInfo;
    }

    private Collection<GuestCount> translateGuestCounts(ReservationRoomStayDTO reservationRoomStayDTO) {
        List<GuestCount> guestCounts = new ArrayList<GuestCount>();
        GuestCount adult = new GuestCount();
        adult.setCount(reservationRoomStayDTO.getAdultCount());
        adult.setAgeQualifyingCode(ADULT_QUALITY_CODE);
        guestCounts.add(adult);
        if (reservationRoomStayDTO.getChildCount() > 0) {
            GuestCount children = new GuestCount();
            children.setAgeQualifyingCode(CHILD_QUALITY_CODE);
            children.setCount(reservationRoomStayDTO.getChildCount());
            guestCounts.add(children);
        }
        return guestCounts;
    }

    private Guarantee translateGuarantee() {
        Guarantee guarantee = new Guarantee();
        guarantee.setGuaranteeCode(DEFAULT_GUARANTEE_CODE);
        return guarantee;
    }

    private Guests createResGuests(HotelReservationRequest reservationRequest) {
        List<CustomerDTO> customerDTOs =
                reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getGuestsList();
        if (CollectionUtil.isEmpty(customerDTOs)) {
            return null;
        }
        Guests guests = new Guests();
        guests.getResGuest().addAll(translateGuests(customerDTOs));

        ReservationRoomStayDTO reservationRoomStayDTO = reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0);
        if (reservationRoomStayDTO == null || CollectionUtil.isEmpty(reservationRoomStayDTO.getGuaranteesList())) {
            return guests;
        }
        setGuarantee(guests.getResGuest(), reservationRoomStayDTO.getGuaranteesList());
        return guests;
    }

    private List<ResGuest> translateGuests(List<CustomerDTO> customerDTOs) {
        List<ResGuest> resGuests = new ArrayList<ResGuest>();
        Customer firstCustomer = null;
        for (CustomerDTO customerDTO : customerDTOs) {
            PersonNameDTO personName = customerDTO.getPersonName();
            if (firstCustomer == null) {
                firstCustomer = new Customer();
                firstCustomer.setPersonName(createPersonName(personName));
                if (CollectionUtil.isNotEmpty(customerDTO.getTelephonesList())) {
                    firstCustomer.setTelephone(translateTelephone(customerDTO.getTelephonesList()));
                }
                if (CollectionUtil.isNotEmpty(customerDTO.getEmailsList())) {
                    firstCustomer.setEmail(translateEmail(customerDTO.getEmailsList()));
                }
                Address address = null;
                if (CollectionUtil.isNotEmpty(customerDTO.getAddressesList())) {
                    address = new Address();
                    address.getAddressLine().add(customerDTO.getAddressesList().get(0));
                }
                if (address != null) {
                    firstCustomer.setAddress(address);
                }
                Profiles profiles = new Profiles();
                profiles.getProfileInfo().add(createProfile(firstCustomer));
                ResGuest resGuest = new ResGuest();
                resGuest.setProfiles(profiles);
                resGuests.add(resGuest);
            } else {
                PersonName otherCustomerName = createPersonName(personName);
                Customer otherCustomer = new Customer();
                otherCustomer.setPersonName(otherCustomerName);
                otherCustomer.setAddress(firstCustomer.getAddress());
                otherCustomer.setEmail(firstCustomer.getEmail());
                otherCustomer.setTelephone(firstCustomer.getTelephone());

                Profiles profiles = new Profiles();
                profiles.getProfileInfo().add(createProfile(otherCustomer));
                ResGuest otherResGuest = new ResGuest();
                otherResGuest.setProfiles(profiles);
                resGuests.add(otherResGuest);
            }
        }
        return resGuests;
    }

    private Profile createProfile(Customer customer) {
        Profile profile = new Profile();
        ProfileType profileType = new ProfileType();
        profileType.setCustomer(customer);
        profile.setProfile(profileType);
        return profile;
    }

    private String translateEmail(List<String> emails) {
        if (CollectionUtil.isEmpty(emails)) {
            return BLANK;
        }
        StringBuilder builder = new StringBuilder();
        for (String email : emails) {
            builder.append(email);
            builder.append(";");
        }
        String result = builder.toString();

        return result.substring(0, result.length() - 1);
    }

    private Telephone translateTelephone(List<TelephoneDTO> telephones) {
        StringBuilder builder = new StringBuilder();
        for (TelephoneDTO telephone : telephones) {
            builder.append(telephone.getNumber());
            builder.append(";");
        }
        String result = builder.toString();
        if (StringUtils.isBlank(result)) {
            return null;
        }
        Telephone telephone = new Telephone();
        telephone.setPhoneNumber(result.substring(0, result.length() - 1));
        return telephone;
    }

    private String translateCardCode(String code) {
        if (code.equals("AE")) {
            return "AX";
        }
        return code;
    }

    private PersonName createPersonName(PersonNameDTO personNameDTO) {
        PersonName personName = new PersonName();
        personName.setSurname(BadCharacterUtils.filterName(personNameDTO.getSurname()));
        personName.setGivenName(BadCharacterUtils.filterName(personNameDTO.getGivenName()));
        return personName;
    }

    private void setGuarantee(List<ResGuest> resGuests, List<GuaranteeDTO> guaranteeDTOs) {
        PaymentCardDTO paymentCardDTO = guaranteeDTOs.get(0).getPaymentCard();
        if (paymentCardDTO != null) {
            PaymentCard paymentCard = new PaymentCard();
            paymentCard.setCardCode(translateCardCode(paymentCardDTO.getCardCode()));
            paymentCard.setCardNumber(paymentCardDTO.getCardNumber());
            paymentCard.setExpireDate(paymentCardDTO.getExpireDate());
            PaymentForm paymentForm = new PaymentForm();
            paymentForm.setPaymentCard(paymentCard);

            for (ResGuest resGuest : resGuests) {
                resGuest.getProfiles().getProfileInfo().get(0).getProfile().getCustomer().setPaymentForm(paymentForm);
            }
        }
    }
}
